package com.lagou.edu.utils;

import com.google.common.base.Strings;
import com.lagou.edu.annotation.Component;
import com.lagou.edu.annotation.Repository;
import com.lagou.edu.annotation.Service;
import com.lagou.edu.ioc.BeanDefinition;

import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author Kirito
 * @description:
 * @date 2020/04/04
 */
public class PackagingScanUtils {

    private Set<BeanDefinition> beanDefinitions = new HashSet<>();

    /**
     * 处理beans.xml中配置的包扫描路径
     *
     * @param basePackageName String
     * @return Set
     * @throws Exception Exception
     */
    public Set<BeanDefinition> scanPackage(String basePackageName) throws Exception {
        String path = basePackageName.replaceAll("\\.", "/");
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        Enumeration<URL> resources = classLoader.getResources(path);

        while (resources.hasMoreElements()) {
            URL url = resources.nextElement();
            String filePath = url.getFile();
            File baseFile = new File(filePath);
            File[] files = baseFile.listFiles();
            for (File file : files) {
                String fileName = file.getName();
                if (file.isDirectory()) {
                    scanPackage(basePackageName + "." + file.getName());
                } else {
                    if (file.getName().endsWith(".class")) {
                        int index = fileName.indexOf(".class");
                        fileName = fileName.substring(0, index);
                        String className = basePackageName + "." + fileName;
                        BeanDefinition beanDefinition = dealClass(className);
                        if (null != beanDefinition) {
                            beanDefinitions.add(beanDefinition);
                        }
                    }
                }
            }
        }

        return beanDefinitions;
    }

    /**
     * 处理Class，解析成{@link BeanDefinition}
     *
     * @param className String
     * @return BeanDefinition
     * @throws ClassNotFoundException ClassNotFoundException
     */
    private BeanDefinition dealClass(String className) throws ClassNotFoundException {
        Class<?> clazz = Class.forName(className);
        Service service = clazz.getAnnotation(Service.class);
        Repository repository = clazz.getAnnotation(Repository.class);
        Component component = clazz.getAnnotation(Component.class);
        BeanDefinition beanDefinition = new BeanDefinition();
        beanDefinition.setClazz(clazz);
        List<Class<?>> interfacesList = Arrays.asList(clazz.getInterfaces());
        beanDefinition.setInterfaces(interfacesList);
        if (null != service) {
            beanDefinition.setId(getBeanId(service.value(), clazz.getSimpleName()));
            return beanDefinition;
        } else if (null != repository) {
            beanDefinition.setId(getBeanId(repository.value(), clazz.getSimpleName()));
            return beanDefinition;
        } else if (null != component) {
            beanDefinition.setId(getBeanId(component.value(), clazz.getSimpleName()));
            return beanDefinition;
        }
        return null;
    }

    /**
     * 生成bean id
     * <p>注解value属性不为空，则id=value，否则id=类名首字母小写</p>
     *
     * @param value      String
     * @param simpleName String
     * @return String
     */
    private String getBeanId(String value, String simpleName) {
        if (Strings.isNullOrEmpty(value)) {
            value = firstLetterToLowCase(simpleName);
        }
        return value;
    }

    /**
     * 首字母转小写
     *
     * @param name String
     * @return String
     */
    public String firstLetterToLowCase(String name) {
        char[] chars = name.toCharArray();
        chars[0] += 32;
        name = String.valueOf(chars);
        return name;
    }
}
